import es, popuplib, playerlib, urllib, os.path, cPickle, gamethread, zlib, psyco

psyco.full()
 
music_admins = ["STEAM_0:0:7830569","STEAM_0:1:13575515"]
 
#plugin information
info = es.AddonInfo()
info.name           = "Music"
info.basename       = "streaminmusic" # You should always add this info part!
info.version        = "0.1"
info.author         = "WaRxHeAd, Ojii: Major Improvements, BonBon: Help" #Huge thanks to Sean/Ojii for the php file help/work.
info.url            = "http://www.eventscripts.com/"
info.description    = "Allows you to stream music through a web server."
info.tags           = "admin music stream html php"
 
pathToDB = "%s/songs.db" % es.getAddonPath(info.basename) # Just to make things easier
pathToUsers = "%s/users.db" % es.getAddonPath(info.basename) # Just to make things easier
urlToPHP = "http://71.6.195.82/musicdata.php" # Change this pointing to your php file (http://....)
urlToOKAY = "http://71.6.195.82/musicokay.php" #Change to check if music is "OKAY" :)
urlToZero = "file://%s/stop.html" % es.getAddonPath(info.basename)
plSonglimits = {True:20,False:5} # the strange keys are because of admin detection.
plLimit = 5
webpw = 'flopwns'
KARAOKEINPROGRESS = False

users = {} # This dict will have information about the players volume and whether he wants to listen to music or not
plcreate = {'submitgpl':[],'submitppl':{}}
karaoke = {}
cc = {
      'music':'musicmd',
      'playsong':'playcmd',
      'playlist':'createPlaylist',
      'karaoke':'testKaraoke',
      'cancel':'testKaraokeCancel'}
    
def load():
    global mainmenu, helpmenu, users
    mainmenu = popuplib.easymenu('main_menu','_popup_choice',mainmenu_select)
    mainmenu.settitle('Music Mod')
    mainmenu.addoption(1,'Play a song')
    mainmenu.addoption(2,'Play a playlist')
    mainmenu.addoption(3,'Jukebox')
    mainmenu.addoption(4,'Settings')
    mainmenu.addoption(5,'Help')
    mainmenu.addoption(6,'Stop the Music!')
    helpmenu = popuplib.easymenu('help_menu','_popup_choice',helpmenu_select)
    helpmenu.settitle('Help Menu')
    helpmenu.addoption(1,'What is This Music Mod?')
    helpmenu.addoption(2,'Playing a Song')
    helpmenu.addoption(3,'Playing a Playlist')
    helpmenu.addoption(4,'Making a Playlist')
    if os.path.exists(pathToUsers):
        f = open(pathToUsers,'rb')
        users = cPickle.load(f)
        f.close()
    for userid in playerlib.getUseridList('#human'):
        sid = es.getplayersteamid(userid)
        if not users.has_key(sid):
            users[sid] = {'volume':-300,'soundon':True,'admin':False,'playlists':{},'webid':None}
    for steamid in music_admins:
        if users.has_key(steamid):
            users[steamid]['admin'] = True
        else:
            users[steamid] = {'volume':-300,'soundon':True,'admin':True,'playlists':{},'webid':None}
    for c in cc:
        if not es.exists('clientcommand',c):
            es.regclientcmd(c,'streaminmusic/' + cc[c])
        if not es.exists('saycommand','!' + c):
            es.regsaycmd('!' + c,'streaminmusic/' + cc[c])
    getmusicdict() # load the musicdict

es.ServerVar('streaminmusic_version', info['version'], 'Streaminmusic made by Ojii and WaRxHeAd').makepublic()
def unload():
    for c in cc:
        es.unregclientcmd(c)
        es.unregsaycmd('!' + c,)
    f = open(pathToUsers,'wb')
    cPickle.dump(users,f)
    f.close()
 
def round_end(event_var):
    submitPlaylist()
    getmusicdict() # load the musicdict
 
def player_activate(ev):
    global users
    sid = es.getplayersteamid(ev['userid'])
    if not users.has_key(sid):
        users[sid] = {'volume':-300,'soundon':True,'admin':False,'playlists':{},'webid':None}
        
def player_disconnect(ev):
    global plcreate
    if plcreate.has_key(int(ev['userid'])):
        del plcreate[int(ev['userid'])]
 
def _genremenu_select(userid,genre,menuname): # this function is called when a genre is choosen from the menu
    musicmenu2 = popuplib.easymenu('music_menu_2','_popup_choice',_songmenu_select)
    if genre == 'playlist':
        musicmenu2.settitle('Choose a playlist:')
        for playlistid in musicdict['playlists']:
            musicmenu2.addoption('p' + playlistid,musicdict['playlists'][playlistid])
    else:
        musicmenu2.settitle('Choose a song:')
        for songid in musicdict['songs'][genre]:
            musicmenu2.addoption(songid, musicdict['songs'][genre][songid])
    musicmenu2.send(userid)
    
def _songmenu_select(userid,id,menuname): # this function is called when a song is choosen from the menu
    if usr(userid,'admin'):
        adminmenu = popuplib.easymenu('admin_menu','_popup_choice',_adminmenu_select)
        adminmenu.settitle('Choose an option:')
        adminmenu.addoption("all%s" % id,'Play for all players')
        adminmenu.addoption("self%s" % id,'Play for yourself')
        adminmenu.send(userid)
    else:
        _play_sound(id,userid)
            
def _adminmenu_select(userid,choice,menuname):
    if choice.startswith('all'):
        id = choice.replace('all','')
        for userid in playerlib.getUseridList('#human'):
            if usr(userid,'soundon'):
                _play_sound(id,userid)
    elif choice.startswith('self'):
        id = choice.replace('self','')
        _play_sound(id,userid)
    elif choice.startswith('jukeboxall'):
        amount = choice.replace('jukeboxall','')
        for userid in playerlib.getUseridList('#human'):
            if usr(userid,'soundon'):
                jukebox(amount,userid)
    elif choice.startswith('jukeboxself'):
        amount = choice.replace('jukeboxself','')
        jukebox(amount,userid)
 
def _play_sound(songid,userid,preload=0):
    hiddenmotd(userid, 2, "Song Player", "http://71.6.195.82/musicstream.php?song=%s&volume=%s&preload=%s" % (songid,usr(userid,'volume'),preload)) #Change what ever your HTML server is D:

def player_say(event_var):
    userid = int(event_var["userid"])
    if event_var["text"].lower() in ["!musicoff", "musicoff"]:
        usr(userid,'music',False)
        hiddenmotd(userid, 2, "Stop Sound", "http://71.6.195.82/music/stop.html") #You can keep this it just stops the music ;P
    if event_var["text"].lower() in ["!musicon", "musicon"]:
        usr(userid,'music',True)
    if event_var["text"].lower() in ["!music", "music"]:
        mainmenu.send(userid)
        
def musicmd():
    userid = es.getcmduserid()
    if KARAOKEINPROGRESS:
        es.tell(userid,'Karaoke in progress...')
    else:
        mainmenu.send(userid)

def playcmd():
    userid = es.getcmduserid()
    if KARAOKEINPROGRESS:
        es.tell(userid,'Karaoke in progres...')
    else:
        songname = es.getargs().replace(es.getargv(0),'').strip()
        if songname != '':
            id = getSongid(songname)
            if id:
                hiddenmotd(userid, 2, "Song Player", "http://71.6.195.82/musicstream.php?song=%s&volume=%s" % (id,usr(userid,'volume')))
            else:
                es.tell(userid,"Sorry, but your song isn't in our database. Use the command 'music' to get a menu with all songs.")
    
def mainmenu_select(userid,choice,menuname):
    if choice == 1:
        genreMenu(userid)
    elif choice == 2:
        _genremenu_select(userid,'playlist',None)
    elif choice == 3:
        jukebox = popuplib.easymenu('juke_box','_popup_choice',jukebox_choice)
        jukebox.settitle('How many songs should be in the playlist?')
        for number in [2,5,7,10,15,20]:
            jukebox.addoption(number,number)
        jukebox.send(userid)
    elif choice == 4:
        settings = popuplib.easymenu('setting_menu','_popup_choice',settings_select)
        settings.settitle('Settings')
        if usr(userid,'soundon'):
            settings.addoption(1,'Turn music off')
        else:
            settings.addoption(2,'Turn music on')
        settings.addoption(3,'Volume Control')
    elif choice == 5:
        helpmenu.send(userid)
    elif choice == 6:
        hiddenmotd(userid, 2, "Stop Sound", urlToZero)
    else:
        es.tell(userid,'Not available yet')
        
def helpmenu_select(userid,choice,menuname):
    if choice == 1:
        es.tell(userid,'#green','This music mod is designed so players can listen to music by not downloading them and streaming them from a website.')
    elif choice == 2:
        es.tell(userid,'#green','If you want to play a song then go into the music window(typing !music in chat), go into Play a Song, and choose a')
        es.tell(userid,'#green','genre that suits you, and choose your song, it will automatically play.')
    elif choice == 3:
        es.tell(userid,'#green','If you want to play a playlist then go into the music window(typing !music in chant), go to Play a Playlist, and then')
        es.tell(userid,'#green','choose a playlist that you want, you can even create your own!')
    elif choice == 4:
        es.tell(userid,'#green','To make a playlist please type "!playlist <playlistname>" without the brackets, then select songs that you wish to be')
        es.tell(userid,'#green','in your playlist(noone else can see it besides you')
      
def settings_select(userid,choice,menuname):
    if choice == 1:
        usr(userid,'music',False)
    elif choice == 2:
        usr(userid,'music',True)
    elif choice == 3:
        volmenu = popuplib.easymenu('volume_menu','_popup_choice',volumemenu_select)
        volmenu.settitle('Volume')
        volmenu.addoption(0,'10')
        volmenu.addoption(-100,'9')
        volmenu.addoption(-200,'8')
        volmenu.addoption(-300,'7')
        volmenu.addoption(-400,'6')
        volmenu.addoption(-500,'5')
        volmenu.addoption(-600,'4')
        volmenu.addoption(-700,'3')
        volmenu.addoption(-800,'2')
        volmenu.send(userid)
        
def volumemenu_select(userid,choice,menuname):
    usr(userid,'volume',choice)

def jukebox_choice(userid,choice,menuname):
    if usr(userid,'admin'):
        adminmenu = popuplib.easymenu('admin_menu','_popup_choice',_adminmenu_select)
        adminmenu.settitle('Choose an option:')
        adminmenu.addoption("jukeboxall%s" % choice,'Play for all players')
        adminmenu.addoption("jukeboxallself%s" % choice,'Play for yourself')
        adminmenu.send(userid)
    else:
        jukebox(choice,userid)
        
def jukebox(choice,userid):
    hiddenmotd(userid, 2, "Song Player", "http://71.6.195.82/musicstream.php?jukebox=%s&volume=%s" % (choice,usr(userid,'volume')))
    
def genreMenu(userid):
    musicmenu = popuplib.easymenu('music_menu','_popup_choice',_genremenu_select)
    musicmenu.settitle('Select a genre:')
    for genre in musicdict['songs']: # the keys of the musicdict are the genres, so looping through it is fairly easy
        musicmenu.addoption(genre,genre)
    musicmenu.send(userid)
    
def createPlaylist():
    global plcreate
    userid = es.getcmduserid()
    if usr(userid,'admin'):
        if not plcreate.has_key(userid):
            if es.getargc() == 2:
                name = es.getargv(1)
                plcreate[userid] = {'name':name,'list':[]}
                createPlaylistSongloop(userid,1,None)
            else:
                es.tell(userid,'Usage: %s PLAYLISTNAME' % es.getargv(0))
        else:
            es.tell(userid,'You can only create one playlist at a time')
    elif usr(userid,'playlistcount') < plLimit:
        if not plcreate.has_key(userid):
            if es.getargc() == 2:
                name = es.getargv(1)
                plcreate[userid] = {'name':name,'list':[]}
                createPlaylistSongloop(userid,1,None)
            else:
                es.tell(userid,'Usage: %s PLAYLISTNAME' % es.getargv(0))
        else:
            es.tell(userid,'You can only create one playlist at a time')
    else:
        es.tell(userid,'Sorry, but you already reached the limit of personal playlists.')
        
def createPlaylistSongloop(userid,choice,menuname):
    global plcreate
    if choice == 2:
        createPlaylistSave(userid)
    else:
        limit = plSonglimits[usr(userid,'admin')]
        if choice in plcreate[userid]['list']:
            plcreate[userid]['list'].remove(choice)
        else:
            plcreate[userid]['list'].append(choice)
        current = len(plcreate[userid]['list'])
        plcm = popuplib.easymenu('playlist_create_menu','_popup_choice',createPlaylistSongloop)
        plcm.settitle('Choose songs to add or remove (%s/%s)' % (current,limit))
        if type(choice) != int:
            plcm.addoption(2,'Save playlist')
        if current == limit:
            for songid in plcreate[userid]['list']:
                plcm.addoption(songid,"- %s" % getSongname(songid))
        else:
            for genre in musicdict['songs']:
                for songid in musicdict['songs'][genre]:
                    plusminus = '- '
                    if songid in plcreate[userid]['list']:
                        plusminus = '+ '
                    plcm.addoption(songid,"%s%s" % (plusminus,musicdict['songs'][genre][songid]))
        plcm.send(userid)
        
def createPlaylistSave(userid):
    global plcreate
    if usr(userid,'admin'):
        plcreate['submitgpl'].append(plcreate[userid])
    else:
        plcreate['submitppl'][userid].append(plcreate[userid])
    del plcreate[userid]
    es.tell(userid,'Your playlist will be added on next round start')
    
def submitPlaylist():
    global plcreate
    for playlist in plcreate['submit']['submitgpl']:
        name = playlist['name']
        l = ','.join(playlist['list'])
        params = urllib.urlencode({'name':name,'list':l,'pw':webpw})
        urllib.urlopen("%s?ask=submitgpl" % urlToPHP,params)
        es.dbgmsg(1,'Submitted playlist %s' % name)
        
def getmusicdict():
    global musicdict, users
    if os.path.exists(pathToDB): # if there is already a database on the server, open it
        f = open(pathToDB,'rb')
        musicdict = cPickle.load(f) # get the dictionary using cPickle
        f.close()
    else:
        musicdict = {'songs':{},'playlists':{},'karaoke':{}} # Else just create an empty dictionary
    if connection(): # if connection can be established
        params = urllib.urlencode({'pw':webpw})
        u = urllib.urlopen("%s?ask=updates" % urlToPHP,params)
        response = u.read().strip()
        if response == '1':
            # Get deleted songs/playlists
            u = urllib.urlopen("%s?ask=delete" % urlToPHP,params)
            response = u.read()
            if response.replace(' ','') != '':
                dlines = response.splitlines()
                for line in dlines:
                    id = line.strip()
                    if id[0] == 'p':
                        id = id[1:]
                        if musicdict['playlists'].has_key(id):
                            del musicdict['playlists'][id]
                    else:
                        for genre in musicdict['songs']:
                            for song in musicdict['songs'][genre]:
                                if song == id:
                                        del musicdict['songs'][genre][id]
                                        break
            # Get new karaokes
            """
            u = urllib.urlopen('%s?ask=karaoke' % urlToPHP,params)
            response = u.read()
            if response.replace(' ','') != '':
                klines = response.splitlines()
                for line in klines:
                    tkar = {}
                    id, zkar = line.split(' ',1)
                    kars = zlib.decompres(zkar).splitlines()
                    for k in kars:
                        timing, lyric = k.split(' ',1)
                            tkar[timing] = lyric
                    musicdict['karaoke'][id] = tkar
            """
            # Get new users
            """
            u = urllib.urlopen('%s?ask=users' % urlToPHP,params)
            response = u.read()
            if response.replace(' ','') != '':
                ulines = response.splitlines()
                for line in ulines:
                    steamid, webid, admin = line.split(' ',1)
                    a = True
                    if admin != '1':
                        a = False
                    if not users.has_key(steamid):
                        users[steamid] = {'volume':-300,'soundon':True,'admin':a,'playlists':{},'webid':webid}
                    else:
                        users[steamid]['webid'] = webid
                        users[steamid]['admin'] = a
            """
            # Get new songs
            u = urllib.urlopen("%s?ask=add" % urlToPHP,params) # connect to the PHP file
            response = u.read() # read the content
            if response.replace(' ','') != '': # if the response is empty there are no new songs
                alines = response.splitlines() # else we split the lines of the response
                for x in range(0,len(alines),2): # for every set of 2 lines
                    id,title = alines[x].lstrip(' ').split(' ',1) # the title is on the first line
                    genre = alines[x + 1].lstrip(' ') # the genre on the second
                    if not musicdict['songs'].has_key(genre):
                        musicdict['songs'][genre] = {}
                    musicdict['songs'][genre][id] = title
            # Get new playlists
            u = urllib.urlopen("%s?ask=playlists" % urlToPHP,params)
            response = u.read()
            if response.replace(' ','') != '':
                plines = response.splitlines()
                for line in plines:
                    line = line.strip()
                    uid, pid, name = line.split(' ',2)
                    if uid == '0':
                        if not musicdict.has_key('playlists'):
                            musicdict['playlists'] = {}
                        musicdict['playlists'][pid] = name
                    else:
                        steamid = webid(uid)
                        if steamid:
                            if not users[steamid].has_key('playlists'):
                                users[steamid]['playlists'] = {}
                            users[steamid]['playlists'][pid] = name
                        else:
                            es.dbgmsg(0,'WebID %s NOT found!' % uid)
            urllib.urlopen(urlToOKAY,params)
        else:
            es.dbgmsg(0,'No changes on the web')
    else:
        es.dbgmsg(0,'NO CONNECTION!!!')
    f = open(pathToDB,'wb') # save the new databse using cPickle
    cPickle.dump(musicdict,f)
    f.close()
 
def connection(): # to test the connection simply try and error the connection
    try:
        urllib.urlopen(urlToPHP)
        return True
    except:
        return False
       
def hiddenmotd(userid,arg1,arg2,arg3):
    if es.exists('userid',userid):
        es.usermsg('create','motd','VGUIMenu')
        es.usermsg('write','string','motd','info')
        es.usermsg('write','byte','motd',0)
        es.usermsg('write','byte','motd',3)
        es.usermsg('write','string','motd','title')
        es.usermsg('write','string','motd',arg2)
        es.usermsg('write','string','motd','type')
        es.usermsg('write','string','motd',arg1)
        es.usermsg('write','string','motd','msg')
        es.usermsg('write','string','motd',arg3)
        es.usermsg('send','motd',userid)
        es.usermsg('delete','motd')
        es.cexec(userid, 'slot1')
    else:
        es.dbgmsg(0,"usermsg.py: motd: Player: \""+userid+"\" was not found on the server.")
        
def usr(userid,var,change=None):
    global users
    steamid = es.getplayersteamid(userid)
    if var == 'playlistcount':
        x = len(users[steamid]['playlists'])
        if plcreate['submitppl'].has_key(userid):
            x += len(plcreate['submitppl'][userid])
        return x
    if change == None:
        return users[steamid][var]
    else:
        users[steamid][var] = change
        
def webid(id):
    for user in users:
        if users[user].has_key('webid'):
            if users[user]['webid'] == id:
                return user
    return None
        
def getSongname(songid):
    for genre in musicdict['songs']:
        if musicdict['songs'][genre].has_key(songid):
            return musicdict['songs'][genre][songid]
    return None
    
def getSongid(name):
    for genre in musicdict['songs']:
        for id in musicdict['songs'][genre]:
            if musicdict['songs'][genre][id] == name:
                return id
    return None
    
### FOLLOWING FUNCTIONS ARE FOR KARAOKE ###
"""
Info about the karaoke dict layout:
SONGID:{timing_from_the_start_in_seconds:(text,duration_for_text)}
in other words: The dict has songids (strings) as keys. The content is another dict.
That dict has timings as keys (from the start of the song in seconds) and a tuple as value.
The tuple has the line of text as first part and the duration of that line as second part
"""

def testKaraoke():
    global musicdict, karaoke
    userid = es.getcmduserid()
    karaoke[userid] = []
    if not musicdict.has_key('karaoke'):
        musicdict['karaoke'] = {}
    if not musicdict['karaoke'].has_key('17'):
        musicdict['karaoke']['17'] = {4:('I wanna be the very best',3),7:('Like no one ever was...',3),0:('*dunnanananana*',5)}
    if KARAOKEINPROGRESS:
        es.tell(userid,'Karaoke already in progreses...')
    else:
        karaokeMain(userid,'17')
        
def testKaraokeCancel():
    karaokeCancel(es.getcmduserid())

def karaokeMain(userid,songid):
    global karaoke
    if musicdict['karaoke'].has_key(songid):
        timings = musicdict['karaoke'][songid]
        for userid in playerlib.getUseridList('#human'):
            _play_sound(songid,userid,preload=1)
        gamethread.delayedname(15, str(userid) + 'preload', karaokeRun, (userid,songid,timings))
        karaoke[userid].append(str(userid) + 'preload')
        es.tell(userid,'the karaoke is preloading, it will start in 15 seconds!')
    else:
        es.tell(userid,'There are no karaoke timings for this song!')
        
def karaokeRun(userid,songid,timings):
    global karaoke, KARAOKEINPROGRESS
    KARAOKEINPROGRESS = True
    karaoke[userid].remove(str(userid) + 'preload')
    _play_sound(songid,userid,preload=0)
    x = 1
    for timing in timings:
        name = "%s%s" % (userid,x)
        gamethread.delayedname(timing,name,karaokeDisplay,(userid,timings[timing],name))
        karaoke[userid].append(name)
        x += 1
    karaoke[userid].append("%s%s" (userid,'inprogress'))
    gamethread.delayedname(max(timings) + 5,userid + 'inprogress',karaokeCancelProgress,(userid))

def karaokeDisplay(userid,data,name):
    global karaoke
    text,duration = data
    karaoke[userid].remove(name)
    karaokeDisplayLoop(text,duration)
        
def karaokeDisplayLoop(text,duration):
    es.centermsg(text)
    duration -= 1
    if duration:
        gamethread.delayed(1, karaokeDisplayLoop,(text,duration))
            
def karaokeCancel(userid):
    global karaoke, KARAOKEINPROGRESS
    KARAOKEINPROGRESS = False
    for name in karaoke[userid]:
        gamethread.cancelDelayed(name)
    del karaoke[userid]
    
def karaokeCancelProgress(userid):
    global karaoke, KARAOKEINPROGRESS
    KARAOKEINPROGRESS = False
    del karaoke[userid]['inprogress']